package gui;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import java.util.List;
import java.util.ArrayList;

import cards.Card;
import static game.TexasHoldem.MAX_PLAYERS;
import static game.TexasHoldem.COMMUNITY_CARDS;
import static game.TexasHoldem.HOLE_CARDS;

public class Table extends JPanel {
  public static final String CARD_PATH = "./cards/";
  public static final int CARD_WIDTH = 111;
  public static final int CARD_HEIGHT = 161;

  private boolean[] activePlayers;
  private List<Card> playerCards;
  private List<Card> commCards;

  public Table() {
    super();

    /*
     * 9  10  1  2
     * 8  ccccc  3
     * 7   6  5  4
     */
    int width = (int)((8+(4*.2)+3) * CARD_WIDTH)+20;
    int height = (4 * CARD_HEIGHT)+20;

    //      System.out.println(width);
    //      System.out.println(height);

    this.setPreferredSize(new Dimension(width, height));
    this.setSize(width, height);

    playerCards = emptyListOfSize(MAX_PLAYERS*HOLE_CARDS);
    commCards = new ArrayList<Card>();
    activePlayers = new boolean[MAX_PLAYERS];
  }

  private <T> List<T> emptyListOfSize(int size) {
    List<T> ret = new ArrayList<T>(size);
    for (int i = 0; i < size; i++) {
      ret.add(null);
    }
    return ret;
  }

  public void resetCards() {
    playerCards = emptyListOfSize(MAX_PLAYERS*HOLE_CARDS);
    commCards.clear();
    invalidate();
    repaint();
  }

  public void addPlayer(int seat) {
    activePlayers[seat] = true;
    for (int i = 0; i < HOLE_CARDS; i++) {
      playerCards.set(seat*HOLE_CARDS+i, null);
    }
    invalidate();
    repaint();
  }

  public void addCommunityCard(Card c) {
    commCards.add(c);
    invalidate();
    repaint();
  }

  public Card[] getSeatCards(int seat) {
    if (!activePlayers[seat]) {
      throw new IllegalArgumentException("Player in seat is not active: " + seat);
    }
    Card[] cards = new Card[HOLE_CARDS];
    for (int i = 0; i < HOLE_CARDS; i++) {
      cards[i] = playerCards.get(seat*HOLE_CARDS+i);
    }
    return cards;
  }

  public void setPlayerCard(int seat, int card, Card c) {
    if (card > HOLE_CARDS) {
      throw new IllegalArgumentException("Invalid hole card number: " + card);
    }
    if (!activePlayers[seat]) {
      throw new IllegalArgumentException("Player in seat is not active: " + seat);
    }
    playerCards.set(seat*HOLE_CARDS+card, c);
    invalidate();
    repaint();
  }

  private void drawCard(Graphics g, Card c, int x, int y) {
    File source = null;
    if (c == null) {
      // Show card back.
      source = new File(CARD_PATH+"back_01.png");
    } else {
      // Real card.
      source = new File(CARD_PATH+c+".png");
    }
    if (!source.exists()) {
      System.err.println("File does not exist: "+source);
      g.setColor(Color.red);
      g.fillRect(0, 0, getWidth(), getHeight());
    } else {
      // Draw the card.
      Image image = new ImageIcon(source.toString()).getImage();
      g.drawImage(image, x, y, CARD_WIDTH, CARD_HEIGHT, this);
    }
  }

  public void paintComponent(Graphics g) {
    /*
     * 9  10  1  2
     * 8  ccccc  3
     * 7   6  5  4
     */

    if (2 != HOLE_CARDS)
      throw new IllegalStateException(
          "Graphics layout wrong for HOLE_CARDS value.");
    if (5 != COMMUNITY_CARDS)
      throw new IllegalStateException(
          "Graphics layout wrong for COMMUNITY_CARDS value.");
    if (10 != MAX_PLAYERS)
      throw new IllegalStateException(
          "Graphics layout wrong for MAX_PLAYERS value.");

    int[] xc = new int[15];
    int[] yc = new int[15];
    int spacer = (int)(CARD_WIDTH * 0.2);

    yc[8] = yc[9] = yc[0] = yc[1] = 10;
    yc[7] =                 yc[2] = (getHeight()/2) - (CARD_HEIGHT/2);
    yc[6] = yc[5] = yc[4] = yc[3] = getHeight()-(CARD_HEIGHT+10);
    // Comm cards.
    yc[10] = yc[11] = yc[12] = yc[13] = yc[14] = yc[7];

    xc[8] = xc[7] = xc[6] = 10;
    xc[9] = xc[5] = xc[8]+3*CARD_WIDTH+spacer;
    xc[1] = xc[2] = xc[3] = getWidth()-(2*CARD_WIDTH+spacer+10);
    xc[0] = xc[4] = xc[1]-(3*CARD_WIDTH+spacer);
    // Comm cards
    xc[12] = ((xc[2]-(xc[7]+(2*CARD_WIDTH+spacer)))/2)+(xc[7]+2*CARD_WIDTH+spacer)-(CARD_WIDTH/2);
    xc[13] = xc[12]+CARD_WIDTH+spacer;
    xc[14] = xc[13]+CARD_WIDTH+spacer;
    xc[11] = xc[12]-CARD_WIDTH-spacer;
    xc[10] = xc[11]-CARD_WIDTH-spacer;

    // Dark Green
    g.setColor(new Color(0x00, 0x64, 0x00));
    g.fillRect(0, 0, getWidth(), getHeight());

    for (int i = 0; i < MAX_PLAYERS; i++) {
      if (!activePlayers[i])
        continue;
      Card[] cards = getSeatCards(i);

      // Draw the card outlines.
      g.setColor(Color.black);
      g.drawRect(xc[i]-2, yc[i]-2, CARD_WIDTH+4, CARD_HEIGHT+4);
      g.drawRect((xc[i]+CARD_WIDTH+spacer)-2, yc[i]-2, CARD_WIDTH+4, CARD_HEIGHT+4);

      // TODO: allow arbitrary names, position somewhere better
      char[] playerName = ("" + i).toCharArray();
      g.drawChars(playerName, 0, playerName.length, xc[i]+CARD_WIDTH+4, yc[i]+(CARD_HEIGHT/2)+2);

      // Will draw as card back if null
      drawCard(g, cards[0], xc[i], yc[i]);
      drawCard(g, cards[1], xc[i]+CARD_WIDTH+spacer, yc[i]);
    }

    for (int i = 0; i < COMMUNITY_CARDS; i++) {
      // Draw the card outlines.
      g.setColor(Color.black);
      g.drawRect(xc[10+i]-2, yc[10+i]-2, CARD_WIDTH+4, CARD_HEIGHT+4);

      Card c = null;
      if (commCards.size() > i) {
        c = commCards.get(i);
      }
      drawCard(g, c, xc[10+i], yc[10+i]);
    }

  }

  public static final long serialVersionUID = 1;
}
